package com.wave.system.runner;

import com.wave.common.config.WaveConfig;
import com.wave.system.domain.SysMechanicalArmInfo;
import com.wave.system.mapper.SysMechanicalArmInfoMapper;
import com.wave.system.service.ISysConfigService;
import com.wave.system.service.ISysDictTypeService;
import com.wave.system.thread.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 初始化 system 模块对应业务数据
 *
 * @author Lion Li
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SystemApplicationRunner implements ApplicationRunner {

    public static Map<String, Socket> socketMap = new ConcurrentHashMap<>();
    public static List<SysMechanicalArmInfo> armList = new ArrayList<>();

    private final WaveConfig waveConfig;
    private final ISysConfigService configService;
    private final ISysDictTypeService dictTypeService;
    private final ThreadPoolExecutor threadPoolExecutor;
    private final SysMechanicalArmInfoMapper sysMechanicalArmInfoMapper;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (waveConfig.isCacheLazy()) {
            return;
        }
        configService.loadingConfigCache();
        log.info("加载参数缓存数据成功");
        dictTypeService.loadingDictCache();
        log.info("加载字典缓存数据成功");

        List<SysMechanicalArmInfo> mechanicalArmInfos = sysMechanicalArmInfoMapper.selectList();
        armList.addAll(mechanicalArmInfos);

        //视觉server端
        threadPoolExecutor.submit(() -> {
            try {
                ServerSocket ss = new ServerSocket(6000);
                log.info("视觉服务端启动成功，端口：6000");
                while (true) {
                    Socket socket = ss.accept();
                    InetSocketAddress remoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
                    log.info("视觉客户端{}上线了,port:{}", remoteSocketAddress.getHostName(), remoteSocketAddress.getPort());
                    socketMap.put("visualSocket", socket);
                }
            } catch (Exception e) {
                log.error("视觉server端启动失败", e);
            }
        });

        threadPoolExecutor.submit(new EmptyShelfArriveListenerThread());
        threadPoolExecutor.submit(new B1SV1AllowScanCodeListenerThread());
        threadPoolExecutor.submit(new A1RobotScanCodeListenerThread());
        threadPoolExecutor.submit(new A3RobotScanCodeListenerThread());
        threadPoolExecutor.submit(new PlaceMaterialFinishA1ListenerThread());
        threadPoolExecutor.submit(new PlaceMaterialFinishA3ListenerThread());
        threadPoolExecutor.submit(new PathPoint1ListenerThread());
        threadPoolExecutor.submit(new PathPoint2ListenerThread());
        threadPoolExecutor.submit(new PathPoint3ListenerThread());
        //threadPoolExecutor.submit(new ShipmentFinishListenerThread());
        threadPoolExecutor.submit(new RobotStatusListenerThread());

    }

    /**
     * 根据视觉获取产品sn编码
     *
     * @param type = 1代表A1机器人，type = 3代表A3机器人，
     * @return
     * @throws IOException
     */
    public static String getVisualCode(Socket socket, int type) throws IOException {
        OutputStream outputStream = socket.getOutputStream();
        if (1 == type) {
            log.info("A1机器人开始拍照");
            outputStream.write("start2".getBytes());
        }
        if (3 == type) {
            log.info("A3机器人开始拍照");
            outputStream.write("start1".getBytes());
        }
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        try {
            int read = inputStream.read(bytes);
            String result = new String(bytes, 0, read);
            log.info("A{}视觉信号：{}", type, result);
            if (StringUtils.isNotBlank(result)) {
                String[] split = result.split(";");
                if (split.length > 1) {
                    String snCode = split[1];
                    log.info("A{}视觉产品编码：{}", type, snCode);
                    if (StringUtils.isNotEmpty(snCode) && !"NoRead".equals(snCode)) {
                        return snCode;
                    }
                }
            }
        } catch (Exception e) {
            log.error("A{}视觉客户端下线了：{}", type, socket.getRemoteSocketAddress(), e);
            socket.close();
            return null;
        }
        return null;
    }


    /**
     * 重试拍照三次
     * @param socket
     * @param type
     * @return
     * @throws Exception
     */
    public static synchronized String getVisualCodeByRetry(Socket socket, int type) throws Exception {
        int i = 0;
        while (i < 3) {
            i++;
            String visualCode = getVisualCode(socket, type);
            if (StringUtils.isNotEmpty(visualCode)) {
                return visualCode;
            }
            TimeUnit.SECONDS.sleep(1);
        }
        return null;
    }
}
